﻿

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using Isuka.Spiritual.Auxiliaries;

namespace Isuka.Spiritual
{
	partial class RuleHolder<T, A>
	{
		public static RuleHolder<T, A> operator |(RuleHolder<T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Or(right.Rule));
		}
		
		public static RuleHolder<T, A> operator |(RuleHolder<T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Or(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator |(RuleHolder<T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Or(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator |(T left, RuleHolder<T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Or(right.Rule));
		}

		public static RuleHolder<T, A> operator |(IEnumerable<T> left, RuleHolder<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Or(right.Rule));
		}

		public static RuleHolder<T, A> operator &(RuleHolder<T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.And(right.Rule));
		}
		
		public static RuleHolder<T, A> operator &(RuleHolder<T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.And(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator &(RuleHolder<T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.And(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator &(T left, RuleHolder<T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).And(right.Rule));
		}

		public static RuleHolder<T, A> operator &(IEnumerable<T> left, RuleHolder<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).And(right.Rule));
		}

		public static RuleHolder<T, A> operator %(RuleHolder<T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Pipe(right.Rule));
		}
		
		public static RuleHolder<T, A> operator %(RuleHolder<T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Pipe(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator %(RuleHolder<T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Pipe(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator %(T left, RuleHolder<T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Pipe(right.Rule));
		}

		public static RuleHolder<T, A> operator %(IEnumerable<T> left, RuleHolder<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Pipe(right.Rule));
		}

	}

	partial class ValueConvertibleRule<V, T, A>
	{
		public static RuleHolder<T, A> operator |(ValueConvertibleRule<V, T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Or(right.Rule));
		}
		
		public static RuleHolder<T, A> operator |(ValueConvertibleRule<V, T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Or(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator |(ValueConvertibleRule<V, T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Or(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator |(T left, ValueConvertibleRule<V, T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Or(right.Rule));
		}

		public static RuleHolder<T, A> operator |(IEnumerable<T> left, ValueConvertibleRule<V, T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Or(right.Rule));
		}

		public static RuleHolder<T, A> operator &(ValueConvertibleRule<V, T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.And(right.Rule));
		}
		
		public static RuleHolder<T, A> operator &(ValueConvertibleRule<V, T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.And(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator &(ValueConvertibleRule<V, T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.And(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator &(T left, ValueConvertibleRule<V, T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).And(right.Rule));
		}

		public static RuleHolder<T, A> operator &(IEnumerable<T> left, ValueConvertibleRule<V, T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).And(right.Rule));
		}

		public static RuleHolder<T, A> operator %(ValueConvertibleRule<V, T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Pipe(right.Rule));
		}
		
		public static RuleHolder<T, A> operator %(ValueConvertibleRule<V, T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Pipe(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator %(ValueConvertibleRule<V, T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.Rule.Pipe(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator %(T left, ValueConvertibleRule<V, T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Pipe(right.Rule));
		}

		public static RuleHolder<T, A> operator %(IEnumerable<T> left, ValueConvertibleRule<V, T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Pipe(right.Rule));
		}

	}

	partial class RuleReference<T, A>
	{
		public static RuleHolder<T, A> operator |(RuleReference<T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.Or(right.Rule));
		}
		
		public static RuleHolder<T, A> operator |(RuleReference<T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.Or(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator |(RuleReference<T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.Or(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator |(T left, RuleReference<T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Or(right.RuleGet));
		}

		public static RuleHolder<T, A> operator |(IEnumerable<T> left, RuleReference<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Or(right.RuleGet));
		}

		public static RuleHolder<T, A> operator &(RuleReference<T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.And(right.Rule));
		}
		
		public static RuleHolder<T, A> operator &(RuleReference<T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.And(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator &(RuleReference<T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.And(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator &(T left, RuleReference<T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).And(right.RuleGet));
		}

		public static RuleHolder<T, A> operator &(IEnumerable<T> left, RuleReference<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).And(right.RuleGet));
		}

		public static RuleHolder<T, A> operator %(RuleReference<T, A> left, IRule<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.Pipe(right.Rule));
		}
		
		public static RuleHolder<T, A> operator %(RuleReference<T, A> left, T right)
		{
			Contract.Requires(left != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.Pipe(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator %(RuleReference<T, A> left, IEnumerable<T> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(left.RuleGet.Pipe(Rules<T, A>._Eq(right)));
		}

		public static RuleHolder<T, A> operator %(T left, RuleReference<T, A> right)
		{
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Pipe(right.RuleGet));
		}

		public static RuleHolder<T, A> operator %(IEnumerable<T> left, RuleReference<T, A> right)
		{
			Contract.Requires(left != null);
			Contract.Requires(right != null);
			Contract.Ensures(Contract.Result<RuleHolder<T, A>>() != null);

			return new RuleHolder<T, A>(Rules<T, A>._Eq(left).Pipe(right.RuleGet));
		}

	}

}